package com.yuanhua.xcxmng.wechat.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yuanhua.xcxmng.wechat.cache.LocalCache;
import com.yuanhua.xcxmng.wechat.entity.User;
import com.yuanhua.xcxmng.wechat.entity.UserAll;
import com.yuanhua.xcxmng.wechat.entity.UserRun;
import com.yuanhua.xcxmng.wechat.entity.UserTarget;
import com.yuanhua.xcxmng.wechat.job.UpdateNoTask;

import com.yuanhua.xcxmng.wechat.service.MyService;
import com.yuanhua.xcxmng.wechat.service.TargetYesService;
import com.yuanhua.xcxmng.wechat.service.UserDeviceService;
import com.yuanhua.xcxmng.wechat.utils.Base64Util;
import com.yuanhua.xcxmng.wechat.utils.JsonUtils;
import com.yuanhua.xcxmng.wechat.utils.Pkcs7Encoder;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;

/**
 * 微信小程序用户接口
 *
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */
@RestController
@RequestMapping("/wechat/user")
public class WxMaUserController extends BaseController {

    @Autowired
    private WxMaService       wxService;

    @Autowired
    private MyService         myService;

    @Autowired
    private TargetYesService  targetYesService;

    @Autowired
    private UpdateNoTask      updateNoTask;
    @Resource
    private UserDeviceService userDeviceService;

    /**
     * 登陆接口
     */
    @GetMapping("login")
    public String login(String code) {
        if (StringUtils.isBlank(code)) {
            return "empty jscode";
        }
        try {
            WxMaJscode2SessionResult session = this.wxService.getUserService().getSessionInfo(code);
            this.logger.info(session.getSessionKey());
            this.logger.info(session.getOpenid());
            String threeSession = UUID.randomUUID().toString();
            LocalCache cache = LocalCache.getInStance();
            cache.setLocalCache(threeSession, 3000000, session.getSessionKey() + "^#^" + session.getOpenid());
            //TODO 可以增加自己的逻辑，关联业务相关数据
            return JsonUtils.toJson(threeSession);
        } catch (WxErrorException e) {
            this.logger.error(e.getMessage(), e);
            return e.toString();
        }
    }

    /**
     * 登陆接口
     */
    @GetMapping("findUserByThreeSession")
    public String findUserByThreeSession(String threeSession) {
        if (StringUtils.isBlank(threeSession)) {
            return "empty threeSession";
        }
        try {
            String sessionCode = LocalCache.getInStance().getLocalCache(threeSession);
            if (StringUtils.isBlank(sessionCode)) {
                return "fail";
            }
            String openId = StringUtils.split(sessionCode, "^#^")[1];

            User exists = myService.findUserByOpenId(openId);
            if(exists!=null){
                return JsonUtils.toJson(exists);
            }else{
                return JsonUtils.toJson("fail");
            }
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
            return e.toString();
        }
    }

    /**
     * 登陆接口
     */
    @GetMapping("createUser")
    public String createUser(String threeSession, String touxiang, String nickName, int gender) {
        if (StringUtils.isBlank(threeSession)) {
            return "empty threeSession";
        }
        try {
            updateNoTask.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            String sessionCode = LocalCache.getInStance().getLocalCache(threeSession);
            if (StringUtils.isBlank(sessionCode)) {
                return "fail";
            }
            String openId = StringUtils.split(sessionCode, "^#^")[1];

            User exists = myService.findUserByOpenId(openId);
            logger.info("createuser : " + JsonUtils.toJson(exists));
            if (exists != null) {
                exists.setNickName(nickName);
                exists.setTouxiang(touxiang);
                myService.updateUser(exists);
                createTarget(gender, openId);
                exists.setDeviceId(userDeviceService.getBindingDeviceIdByOpenId(openId));
                return JsonUtils.toJson(exists);
            }
            User user = createUser(touxiang, nickName, gender, openId);
            createTarget(gender, openId);
            return JsonUtils.toJson(user);
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
            return e.toString();
        }
    }

    private User createUser(String touxiang, String nickName, int gender, String openId) throws Exception {
        User user = new User();
        user.setAge("");
        user.setOpenId(openId);
        user.setUnionId(StringUtils.EMPTY);
        user.setNickName(nickName);
        user.setTouxiang(StringUtils.trimToEmpty(touxiang));
        user.setCurrency(Long.valueOf(0));
        user.setStep(0L);
        user.setNo(0);
        user.setPreNo(0);
        user.setGender(gender);
        user.setHeight(0);
        user.setUnit("kg");
        myService.createUser(user);
        return user;
    }

    private void createTarget(int gender, String openId) throws Exception {
        if (myService.findTargetByOpenId(openId) != null) {
            return;
        }
        UserTarget defaultTarget = new UserTarget();
        defaultTarget.setOpenId(openId);
        defaultTarget.setGmtCreate(new Date());
        defaultTarget.setGmtUpdate(new Date());
        defaultTarget.setTargetDgc(new BigDecimal(6.0));
        defaultTarget.setTargetGysz(new BigDecimal(1.7));
        defaultTarget.setTargetStep(10000L);
        defaultTarget.setTargetNs(gender == 1 ? new BigDecimal(416) : new BigDecimal(357));
        defaultTarget.setTargetXtCq(new BigDecimal(6.1));
        defaultTarget.setTargetXtCh(new BigDecimal(7.8));
        myService.createTarget(defaultTarget);
    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @GetMapping("info")
    public String info(String threeSession, String signature, String rawData, String encryptedData, String iv) throws Exception {

        String sessionCode = LocalCache.getInStance().getLocalCache(threeSession);
        if (StringUtils.isBlank(sessionCode)) {
            return "fail";
        }
        String sessionKey = StringUtils.split(sessionCode, "^#^")[0];
        String openId = StringUtils.split(sessionCode, "^#^")[1];
        // 用户信息校验
        if (!this.wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
            return "user check failed";
        }

        // 解密用户信息
        WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
        this.logger.warn("WxMaUserInfo: {}",userInfo);
        User user = myService.findUserByOpenId(openId);
        if (user.getGender() != null && user.getGender() != null) {
            userInfo.setGender(user.getGender() + "");
        }

        return JsonUtils.toJson(userInfo);
    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @GetMapping("run")
    public String run(String threeSession, String res, String rawData, String encryptedData, String iv) {
        // 用户信息校验
        if (StringUtils.isBlank(threeSession)) {
            return "empty threeSession";
        }
        String sessionCode = LocalCache.getInStance().getLocalCache(threeSession);
        if (StringUtils.isBlank(sessionCode)) {
            return "fail";
        }
        String sessionKey = StringUtils.split(sessionCode, "^#^")[0];
        String openId = StringUtils.split(sessionCode, "^#^")[1];
        JSONObject jsonObject = JSON.parseObject(res);
        encryptedData = jsonObject.get("encryptedData").toString();
        iv = jsonObject.get("iv").toString();

        try {
            byte[] en = Base64Util.decodeString(encryptedData);
            byte[] sessionkeyByte = Base64Util.decodeString(sessionKey);
            byte[] ivs = Base64Util.decodeString(iv);
            byte[] result = Pkcs7Encoder.decryptOfDiyIV(en, sessionkeyByte, ivs);
            String str = new String(result);
            JSONObject object = JSON.parseObject(str);
            JSONArray jsonArray = object.getJSONArray("stepInfoList");
            synchronized (openId) {
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject obj = jsonArray.getJSONObject(i);
                    Long step = NumberUtils.toLong(obj.get("step").toString(), 0L);
                    Long timestamp = NumberUtils.toLong(obj.get("timestamp").toString(), 0L);
                    Date gmtDate = new Date(timestamp * 1000);
                    UserRun userRun = myService.findRunDataByOpenIdDate(openId, gmtDate);
                    if (userRun == null) {
                        myService.saveRunData(openId, gmtDate, step);
                    } else if (!step.equals(userRun.getStep())) {
                        userRun.setStep(step);
                        myService.updateUserRun(userRun);
                    }
                }
            }
            targetYesService.targetYes(openId);
            JSONObject obj = jsonArray.getJSONObject(jsonArray.size() - 1);
            User user = myService.findUserByOpenId(openId);
            Long step = NumberUtils.toLong(obj.get("step").toString(), 0L);
            user.setStep(step);
            myService.updateUser(user);
            updateNoTask.execute();
            return JsonUtils.toJson(step);
        } catch (Exception e) {
            return "fail";
        }

    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @GetMapping("target")
    public String target(String threeSession) {
        // 用户信息校验
        if (StringUtils.isBlank(threeSession)) {
            return "empty threeSession";
        }
        String sessionCode = LocalCache.getInStance().getLocalCache(threeSession);
        if (StringUtils.isBlank(sessionCode)) {
            return "fail";
        }
        String sessionKey = StringUtils.split(sessionCode, "^#^")[0];
        String openId = StringUtils.split(sessionCode, "^#^")[1];

        try {
            UserTarget userTarget = myService.findTargetByOpenId(openId);
            if (userTarget != null) {
                return JsonUtils.toJson(userTarget);
            }
            return JsonUtils.toJson(new UserTarget());
        } catch (Exception e) {
            return "fail";
        }
    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @GetMapping("setTarget")
    public String setTarget(String threeSession, String types, String value, String value1) {
        // 用户信息校验
        if (StringUtils.isBlank(threeSession)) {
            return "empty threeSession";
        }
        String sessionCode = LocalCache.getInStance().getLocalCache(threeSession);
        if (StringUtils.isBlank(sessionCode)) {
            return "fail";
        }
        String sessionKey = StringUtils.split(sessionCode, "^#^")[0];
        String openId = StringUtils.split(sessionCode, "^#^")[1];
        try {
            if ("age".equals(types)) {
                User user = myService.findUserByOpenId(openId);
                user.setAge(value);
                myService.updateUser(user);
                return "success";
            }
            if ("height".equals(types) && StringUtils.isNumeric(value)) {
                User user = myService.findUserByOpenId(openId);
                user.setHeight(Integer.valueOf(value));
                myService.updateUser(user);
                return "success";
            }

            if ("unit".equals(types)) {
                User user = myService.findUserByOpenId(openId);
                user.setUnit(value);
                myService.updateUser(user);
                return "success";
            }

            if ("gender".equals(types)) {
                User user = myService.findUserByOpenId(openId);
                user.setGender(NumberUtils.toInt(value));
                myService.updateUser(user);
                return "success";
            }
            UserTarget exists = myService.findTargetByOpenId(openId);
            if (exists == null) {
                UserTarget userTarget = new UserTarget();
                userTarget.setGmtCreate(new Date());
                userTarget.setGmtUpdate(new Date());
                userTarget.setOpenId(openId);
                if ("step".equals(types)) {
                    userTarget.setTargetStep(NumberUtils.toLong(value));
                    userTarget.setTargetXtCq(new BigDecimal(0));
                    userTarget.setTargetXtCh(new BigDecimal(0));
                    userTarget.setTargetNs(new BigDecimal(0));
                    userTarget.setTargetDgc(new BigDecimal(0));
                    userTarget.setTargetGysz(new BigDecimal(0));
                } else if ("xt".equals(types)) {
                    userTarget.setTargetXtCq(new BigDecimal(value));
                    userTarget.setTargetXtCh(new BigDecimal(value1));
                    userTarget.setTargetNs(new BigDecimal(0));
                    userTarget.setTargetDgc(new BigDecimal(0));
                    userTarget.setTargetGysz(new BigDecimal(0));
                    userTarget.setTargetStep(0L);
                } else if ("ns".equals(types)) {
                    userTarget.setTargetNs(new BigDecimal(value));
                    userTarget.setTargetDgc(new BigDecimal(0));
                    userTarget.setTargetGysz(new BigDecimal(0));
                    userTarget.setTargetXtCq(new BigDecimal(0));
                    userTarget.setTargetXtCh(new BigDecimal(0));
                    userTarget.setTargetStep(0L);
                } else if ("dgc".equals(types)) {
                    userTarget.setTargetDgc(new BigDecimal(value));
                    userTarget.setTargetNs(new BigDecimal(0));
                    userTarget.setTargetGysz(new BigDecimal(0));
                    userTarget.setTargetXtCq(new BigDecimal(0));
                    userTarget.setTargetXtCh(new BigDecimal(0));
                    userTarget.setTargetStep(0L);
                } else if ("gysz".equals(types)) {
                    userTarget.setTargetGysz(new BigDecimal(value));
                    userTarget.setTargetDgc(new BigDecimal(0));
                    userTarget.setTargetNs(new BigDecimal(0));
                    userTarget.setTargetXtCq(new BigDecimal(0));
                    userTarget.setTargetXtCh(new BigDecimal(0));
                    userTarget.setTargetStep(0L);
                }
                myService.createTarget(userTarget);
            } else {
                exists.setGmtUpdate(new Date());
                if ("step".equals(types)) {
                    exists.setTargetStep(NumberUtils.toLong(value));
                } else if ("xt".equals(types)) {
                    exists.setTargetXtCq(new BigDecimal(value));
                    exists.setTargetXtCh(new BigDecimal(value1));
                } else if ("ns".equals(types)) {
                    exists.setTargetNs(new BigDecimal(value));
                } else if ("dgc".equals(types)) {
                    exists.setTargetDgc(new BigDecimal(value));
                } else if ("gysz".equals(types)) {
                    exists.setTargetGysz(new BigDecimal(value));
                }
                myService.updateTarget(exists);
            }
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        }
    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @GetMapping("mine")
    public String user(String threeSession) {
        // 用户信息校验
        if (StringUtils.isBlank(threeSession)) {
            return "empty threeSession";
        }
        String sessionCode = LocalCache.getInStance().getLocalCache(threeSession);
        if (StringUtils.isBlank(sessionCode)) {
            return "fail";
        }
        String sessionKey = StringUtils.split(sessionCode, "^#^")[0];
        String openId = StringUtils.split(sessionCode, "^#^")[1];

        try {
            UserTarget userTarget = myService.findTargetByOpenId(openId);
            User user = myService.findUserByOpenId(openId);
            UserAll userAll = new UserAll();
            userAll.setUser(user);
            userAll.setTarget(userTarget);
            return JsonUtils.toJson(userAll);
        } catch (Exception e) {
            return "fail";
        }
    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @GetMapping("userNo")
    public String userNo(String threeSession) {
        // 用户信息校验
        if (StringUtils.isBlank(threeSession)) {
            return "empty threeSession";
        }
        String sessionCode = LocalCache.getInStance().getLocalCache(threeSession);
        if (StringUtils.isBlank(sessionCode)) {
            return "fail";
        }
        String sessionKey = StringUtils.split(sessionCode, "^#^")[0];
        String openId = StringUtils.split(sessionCode, "^#^")[1];

        try {
            UserTarget userTarget = myService.findTargetByOpenId(openId);
            User user = myService.findUserByOpenId(openId);
            UserAll userAll = new UserAll();
            userAll.setUser(user);
            userAll.setTarget(userTarget);
            return JsonUtils.toJson(userAll);
        } catch (Exception e) {
            return "fail";
        }
    }

}
